{
  "cells": [
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "dotwriter_intro_md"
      },
      "source": [
        "# DotWriter"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "dotwriter_desc_md"
      },
      "source": [
        "The `DotWriter` class is a helper utility in GTSAM used to customize the generation of Graphviz `.dot` file strings for visualizing factor graphs, Bayes nets, and Bayes trees.\n",
        "\n",
        "It allows you to control aspects like figure size, whether factors are plotted as points, how edges are drawn, and specify explicit positions for variables and factors."
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "dotwriter_colab_md"
      },
      "source": [
        "<a href=\"https://colab.research.google.com/github/borglab/gtsam/blob/develop/gtsam/inference/doc/DotWriter.ipynb\" target=\"_parent\"><img src=\"https://colab.research.google.com/assets/colab-badge.svg\" alt=\"Open In Colab\"/></a>"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "dotwriter_pip_code",
        "tags": [
          "remove-cell"
        ]
      },
      "outputs": [],
      "source": [
        "%pip install --quiet gtsam-develop"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 2,
      "metadata": {
        "id": "dotwriter_import_code"
      },
      "outputs": [],
      "source": [
        "import gtsam\n",
        "from gtsam import DotWriter\n",
        "from gtsam import SymbolicFactorGraph # Example graph type\n",
        "from gtsam import symbol_shorthand\n",
        "import graphviz # For rendering\n",
        "import numpy as np\n",
        "\n",
        "X = symbol_shorthand.X\n",
        "L = symbol_shorthand.L"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "dotwriter_create_md"
      },
      "source": [
        "## Creating and Configuring a DotWriter\n",
        "\n",
        "You create a `DotWriter` object and can then modify its public member variables to change the output format."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 3,
      "metadata": {
        "id": "dotwriter_config_code"
      },
      "outputs": [],
      "source": [
        "writer = DotWriter(\n",
        "    figureWidthInches = 8.0,\n",
        "    figureHeightInches = 5.0,\n",
        "    plotFactorPoints = True,      # Draw black dots for factors\n",
        "    connectKeysToFactor = True,   # Draw edges from variables to factor dots\n",
        "    binaryEdges = False           # Don't simplify binary factors to single edges\n",
        ")\n",
        "\n",
        "# --- Configuration Options ---\n",
        "\n",
        "# Specify explicit positions (used by neato -n)\n",
        "writer.variablePositions = {\n",
        "    X(0): gtsam.Point2(0, 0),\n",
        "    X(1): gtsam.Point2(2, 0),\n",
        "    X(2): gtsam.Point2(4, 0),\n",
        "    L(1): gtsam.Point2(1, 2),\n",
        "    L(2): gtsam.Point2(3, 2)\n",
        "}\n",
        "\n",
        "# Specify position hints (alternative, uses symbol char and index)\n",
        "# writer.positionHints = {'x': 0.0, 'l': 2.0} # Puts 'x' vars at y=0, 'l' vars at y=2\n",
        "\n",
        "# Specify which variables should be boxes\n",
        "writer.boxes = {L(1), L(2)}\n",
        "\n",
        "# Specify factor positions (less common)\n",
        "# writer.factorPositions = {3: gtsam.Point2(0.5, 1.0)}"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "dotwriter_usage_md"
      },
      "source": [
        "## Usage with Graph Objects\n",
        "\n",
        "The configured `DotWriter` object is passed as an argument to the `.dot()` method of `FactorGraph`, `BayesNet`, or `BayesTree`."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "dotwriter_graph_code",
        "outputId": "bcdef012-3456-789a-bcde-f0123456789a"
      },
      "outputs": [
        {
          "data": {
            "image/svg+xml": [
              "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n",
              "<!DOCTYPE svg PUBLIC \"-//W3C//DTD SVG 1.1//EN\"\n",
              " \"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd\">\n",
              "<!-- Generated by graphviz version 2.50.0 (0)\n",
              " -->\n",
              "<!-- Pages: 1 -->\n",
              "<svg width=\"350pt\" height=\"84pt\"\n",
              " viewBox=\"0.00 0.00 350.00 83.60\" xmlns=\"http://www.w3.org/2000/svg\" xmlns:xlink=\"http://www.w3.org/1999/xlink\">\n",
              "<g id=\"graph0\" class=\"graph\" transform=\"scale(1 1) rotate(0) translate(4 79.6)\">\n",
              "<polygon fill=\"white\" stroke=\"transparent\" points=\"-4,4 -4,-79.6 346,-79.6 346,4 -4,4\"/>\n",
              "<!-- var7782220156096217089 -->\n",
              "<g id=\"node1\" class=\"node\">\n",
              "<title>var7782220156096217089</title>\n",
              "<polygon fill=\"none\" stroke=\"black\" points=\"126,-75.6 72,-75.6 72,-39.6 126,-39.6 126,-75.6\"/>\n",
              "<text text-anchor=\"middle\" x=\"99\" y=\"-53.9\" font-family=\"Times New Roman,serif\" font-size=\"14.00\">l1</text>\n",
              "</g>\n",
              "<!-- factor3 -->\n",
              "<g id=\"node9\" class=\"node\">\n",
              "<title>factor3</title>\n",
              "<ellipse fill=\"black\" stroke=\"black\" cx=\"75\" cy=\"-1.8\" rx=\"1.8\" ry=\"1.8\"/>\n",
              "</g>\n",
              "<!-- var7782220156096217089&#45;&#45;factor3 -->\n",
              "<g id=\"edge7\" class=\"edge\">\n",
              "<title>var7782220156096217089&#45;&#45;factor3</title>\n",
              "<path fill=\"none\" stroke=\"black\" d=\"M91.41,-39.58C85.25,-25.79 77.31,-7.97 75.42,-3.73\"/>\n",
              "</g>\n",
              "<!-- factor4 -->\n",
              "<g id=\"node10\" class=\"node\">\n",
              "<title>factor4</title>\n",
              "<ellipse fill=\"black\" stroke=\"black\" cx=\"123\" cy=\"-1.8\" rx=\"1.8\" ry=\"1.8\"/>\n",
              "</g>\n",
              "<!-- var7782220156096217089&#45;&#45;factor4 -->\n",
              "<g id=\"edge9\" class=\"edge\">\n",
              "<title>var7782220156096217089&#45;&#45;factor4</title>\n",
              "<path fill=\"none\" stroke=\"black\" d=\"M106.59,-39.58C112.75,-25.79 120.69,-7.97 122.58,-3.73\"/>\n",
              "</g>\n",
              "<!-- var7782220156096217090 -->\n",
              "<g id=\"node2\" class=\"node\">\n",
              "<title>var7782220156096217090</title>\n",
              "<polygon fill=\"none\" stroke=\"black\" points=\"342,-75.6 288,-75.6 288,-39.6 342,-39.6 342,-75.6\"/>\n",
              "<text text-anchor=\"middle\" x=\"315\" y=\"-53.9\" font-family=\"Times New Roman,serif\" font-size=\"14.00\">l2</text>\n",
              "</g>\n",
              "<!-- factor5 -->\n",
              "<g id=\"node11\" class=\"node\">\n",
              "<title>factor5</title>\n",
              "<ellipse fill=\"black\" stroke=\"black\" cx=\"243\" cy=\"-1.8\" rx=\"1.8\" ry=\"1.8\"/>\n",
              "</g>\n",
              "<!-- var7782220156096217090&#45;&#45;factor5 -->\n",
              "<g id=\"edge11\" class=\"edge\">\n",
              "<title>var7782220156096217090&#45;&#45;factor5</title>\n",
              "<path fill=\"none\" stroke=\"black\" d=\"M292.22,-39.58C273.76,-25.79 249.92,-7.97 244.25,-3.73\"/>\n",
              "</g>\n",
              "<!-- factor6 -->\n",
              "<g id=\"node12\" class=\"node\">\n",
              "<title>factor6</title>\n",
              "<ellipse fill=\"black\" stroke=\"black\" cx=\"279\" cy=\"-1.8\" rx=\"1.8\" ry=\"1.8\"/>\n",
              "</g>\n",
              "<!-- var7782220156096217090&#45;&#45;factor6 -->\n",
              "<g id=\"edge13\" class=\"edge\">\n",
              "<title>var7782220156096217090&#45;&#45;factor6</title>\n",
              "<path fill=\"none\" stroke=\"black\" d=\"M303.61,-39.58C294.38,-25.79 282.46,-7.97 279.62,-3.73\"/>\n",
              "</g>\n",
              "<!-- var8646911284551352320 -->\n",
              "<g id=\"node3\" class=\"node\">\n",
              "<title>var8646911284551352320</title>\n",
              "<ellipse fill=\"none\" stroke=\"black\" cx=\"27\" cy=\"-57.6\" rx=\"27\" ry=\"18\"/>\n",
              "<text text-anchor=\"middle\" x=\"27\" y=\"-53.9\" font-family=\"Times New Roman,serif\" font-size=\"14.00\">x0</text>\n",
              "</g>\n",
              "<!-- factor0 -->\n",
              "<g id=\"node6\" class=\"node\">\n",
              "<title>factor0</title>\n",
              "<ellipse fill=\"black\" stroke=\"black\" cx=\"27\" cy=\"-1.8\" rx=\"1.8\" ry=\"1.8\"/>\n",
              "</g>\n",
              "<!-- var8646911284551352320&#45;&#45;factor0 -->\n",
              "<g id=\"edge1\" class=\"edge\">\n",
              "<title>var8646911284551352320&#45;&#45;factor0</title>\n",
              "<path fill=\"none\" stroke=\"black\" d=\"M27,-39.58C27,-25.79 27,-7.97 27,-3.73\"/>\n",
              "</g>\n",
              "<!-- factor1 -->\n",
              "<g id=\"node7\" class=\"node\">\n",
              "<title>factor1</title>\n",
              "<ellipse fill=\"black\" stroke=\"black\" cx=\"100\" cy=\"-1.8\" rx=\"1.8\" ry=\"1.8\"/>\n",
              "</g>\n",
              "<!-- var8646911284551352320&#45;&#45;factor1 -->\n",
              "<g id=\"edge2\" class=\"edge\">\n",
              "<title>var8646911284551352320&#45;&#45;factor1</title>\n",
              "<path fill=\"none\" stroke=\"black\" d=\"M44.67,-43.58C64.25,-29.15 93.78,-7.38 99.15,-3.43\"/>\n",
              "</g>\n",
              "<!-- var8646911284551352320&#45;&#45;factor3 -->\n",
              "<g id=\"edge6\" class=\"edge\">\n",
              "<title>var8646911284551352320&#45;&#45;factor3</title>\n",
              "<path fill=\"none\" stroke=\"black\" d=\"M40.37,-41.61C52.8,-27.68 69.99,-8.41 74.09,-3.81\"/>\n",
              "</g>\n",
              "<!-- var8646911284551352321 -->\n",
              "<g id=\"node4\" class=\"node\">\n",
              "<title>var8646911284551352321</title>\n",
              "<ellipse fill=\"none\" stroke=\"black\" cx=\"171\" cy=\"-57.6\" rx=\"27\" ry=\"18\"/>\n",
              "<text text-anchor=\"middle\" x=\"171\" y=\"-53.9\" font-family=\"Times New Roman,serif\" font-size=\"14.00\">x1</text>\n",
              "</g>\n",
              "<!-- var8646911284551352321&#45;&#45;factor1 -->\n",
              "<g id=\"edge3\" class=\"edge\">\n",
              "<title>var8646911284551352321&#45;&#45;factor1</title>\n",
              "<path fill=\"none\" stroke=\"black\" d=\"M153.81,-43.58C134.77,-29.15 106.05,-7.38 100.83,-3.43\"/>\n",
              "</g>\n",
              "<!-- factor2 -->\n",
              "<g id=\"node8\" class=\"node\">\n",
              "<title>factor2</title>\n",
              "<ellipse fill=\"black\" stroke=\"black\" cx=\"178\" cy=\"-1.8\" rx=\"1.8\" ry=\"1.8\"/>\n",
              "</g>\n",
              "<!-- var8646911284551352321&#45;&#45;factor2 -->\n",
              "<g id=\"edge4\" class=\"edge\">\n",
              "<title>var8646911284551352321&#45;&#45;factor2</title>\n",
              "<path fill=\"none\" stroke=\"black\" d=\"M173.21,-39.58C175.01,-25.79 177.33,-7.97 177.88,-3.73\"/>\n",
              "</g>\n",
              "<!-- var8646911284551352321&#45;&#45;factor4 -->\n",
              "<g id=\"edge8\" class=\"edge\">\n",
              "<title>var8646911284551352321&#45;&#45;factor4</title>\n",
              "<path fill=\"none\" stroke=\"black\" d=\"M157.63,-41.61C145.2,-27.68 128.01,-8.41 123.91,-3.81\"/>\n",
              "</g>\n",
              "<!-- var8646911284551352321&#45;&#45;factor5 -->\n",
              "<g id=\"edge10\" class=\"edge\">\n",
              "<title>var8646911284551352321&#45;&#45;factor5</title>\n",
              "<path fill=\"none\" stroke=\"black\" d=\"M188.43,-43.58C207.74,-29.15 236.87,-7.38 242.16,-3.43\"/>\n",
              "</g>\n",
              "<!-- var8646911284551352322 -->\n",
              "<g id=\"node5\" class=\"node\">\n",
              "<title>var8646911284551352322</title>\n",
              "<ellipse fill=\"none\" stroke=\"black\" cx=\"243\" cy=\"-57.6\" rx=\"27\" ry=\"18\"/>\n",
              "<text text-anchor=\"middle\" x=\"243\" y=\"-53.9\" font-family=\"Times New Roman,serif\" font-size=\"14.00\">x2</text>\n",
              "</g>\n",
              "<!-- var8646911284551352322&#45;&#45;factor2 -->\n",
              "<g id=\"edge5\" class=\"edge\">\n",
              "<title>var8646911284551352322&#45;&#45;factor2</title>\n",
              "<path fill=\"none\" stroke=\"black\" d=\"M226.6,-43.02C209.75,-29.08 185.18,-8.74 179.3,-3.87\"/>\n",
              "</g>\n",
              "<!-- var8646911284551352322&#45;&#45;factor6 -->\n",
              "<g id=\"edge12\" class=\"edge\">\n",
              "<title>var8646911284551352322&#45;&#45;factor6</title>\n",
              "<path fill=\"none\" stroke=\"black\" d=\"M253.61,-40.75C262.9,-26.86 275.37,-8.22 278.34,-3.78\"/>\n",
              "</g>\n",
              "</g>\n",
              "</svg>\n"
            ],
            "text/plain": [
              "<graphviz.sources.Source at 0x1cdd6cacc20>"
            ]
          },
          "execution_count": 4,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "# Create the same graph as in VariableIndex example\n",
        "graph = SymbolicFactorGraph()\n",
        "graph.push_factor(X(0))           # Factor 0\n",
        "graph.push_factor(X(0), X(1))     # Factor 1\n",
        "graph.push_factor(X(1), X(2))     # Factor 2\n",
        "graph.push_factor(X(0), L(1))     # Factor 3\n",
        "graph.push_factor(X(1), L(1))     # Factor 4\n",
        "graph.push_factor(X(1), L(2))     # Factor 5\n",
        "graph.push_factor(X(2), L(2))     # Factor 6\n",
        "\n",
        "# Generate dot string using the configured writer\n",
        "dot_string = graph.dot(writer=writer)\n",
        "\n",
        "# Render the graph\n",
        "graphviz.Source(dot_string)"
      ]
    }
  ],
  "metadata": {
    "colab": {
      "provenance": []
    },
    "kernelspec": {
      "display_name": "gtsam",
      "language": "python",
      "name": "python3"
    },
    "language_info": {
      "codemirror_mode": {
        "name": "ipython",
        "version": 3
      },
      "file_extension": ".py",
      "mimetype": "text/x-python",
      "name": "python",
      "nbconvert_exporter": "python",
      "pygments_lexer": "ipython3",
      "version": "3.13.1"
    }
  },
  "nbformat": 4,
  "nbformat_minor": 0
}
